﻿#include <QDebug>
#include <QThread>
#include <QMap>
#include <QJsonObject>
#include <pdh.h>
#include "qwindowsperformance.h"

QWindowsPerformance::QWindowsPerformance(QObject *parent) :
    QThread(parent),
    runFlag(false),
    m_dataCollectionInterval(1000)
{
}

QWindowsPerformance::~QWindowsPerformance()
{
    stopMonitor();
}

/*
    同步获取本机的某项性能指标

    type：性能类型。
    return：实时性能数值。
*/
double QWindowsPerformance::performance(QWindowsPerformance::PerformanceType type)
{
    double value = 0;

    if(type == QWindowsPerformance::CPUUsageRate)
    {
        PDH_STATUS status = ERROR_SUCCESS;          //PDH api returns code
        DWORD dwCounterType = 0;                    //PDH counter type
        HQUERY hQuery = NULL;                       //PDH query object
        HCOUNTER counter = NULL;
        PDH_FMT_COUNTERVALUE counterValue;

        //Get PDH query object
        status = PdhOpenQuery(NULL, 0, &hQuery);
        if ( status != ERROR_SUCCESS)
        {
            qDebug()<<__FUNCTION__<<" : PdhOpenQuery failed";
            return 0;
        }

        //Add IdleTime counter
        status = PdhAddCounter(hQuery, L"\\Processor(_Total)\\% Idle Time", 0, &counter);
        if (status != ERROR_SUCCESS )
        {
            qDebug()<<__FUNCTION__<<" : PdhAddCounter failed ";
            PdhCloseQuery(hQuery);
            return 0;
        }

        //Collect Data twice
        PdhCollectQueryData(hQuery);
        QThread::msleep(m_dataCollectionInterval);
        PdhCollectQueryData(hQuery);

        //Read Data
        PdhGetFormattedCounterValue(counter,PDH_FMT_DOUBLE,&dwCounterType, &counterValue);
        value = 100-counterValue.doubleValue;

        PdhCloseQuery(hQuery);
    }
    else if(type == QWindowsPerformance::CPURunTime)
    {
        value = GetTickCount64()/1000.0f;
    }
    else if(type == QWindowsPerformance::MemoryUsageRate)
    {
        MEMORYSTATUSEX memStatus;
        memStatus.dwLength = sizeof(memStatus);
        GlobalMemoryStatusEx(&memStatus);

        value = memStatus.dwMemoryLoad;
    }
    else if(type == QWindowsPerformance::MemoryUsageAmount)
    {
        MEMORYSTATUSEX memStatus;
        memStatus.dwLength = sizeof(memStatus);
        GlobalMemoryStatusEx(&memStatus);

        value = (memStatus.ullTotalPhys - memStatus.ullAvailPhys)/1024.0f/1024.0f;
    }
    else if(type == QWindowsPerformance::NetworkDownloadSpeed)
    {
        PDH_STATUS status = ERROR_SUCCESS;
        DWORD dwCounterType = 0;
        HQUERY hQuery = NULL;
        HCOUNTER counter = NULL;
        PDH_FMT_COUNTERVALUE counterValue;

        //Get PDH query object
        status = PdhOpenQuery(NULL, 0, &hQuery);
        if ( status != ERROR_SUCCESS)
        {
            qDebug()<<__FUNCTION__<<" : PdhOpenQuery failed";
            return 0;
        }

        //Add Network counter
        status = PdhAddCounter(hQuery, L"\\Network Interface(*)\\Bytes Received/sec", 0, &counter);
        if (status != ERROR_SUCCESS )
        {
            qDebug()<<__FUNCTION__<<" : PdhAddCounter failed ";
            PdhCloseQuery(hQuery);
            return 0;
        }

        //Collect Data twice
        PdhCollectQueryData(hQuery);
        QThread::msleep(m_dataCollectionInterval);
        PdhCollectQueryData(hQuery);

        //Read Data
        PdhGetFormattedCounterValue(counter,PDH_FMT_DOUBLE,&dwCounterType, &counterValue);
        value = counterValue.doubleValue/1024.0f;

        PdhCloseQuery(hQuery);

    }
    else if(type == QWindowsPerformance::NetworkUploadSpeed)
    {
        PDH_STATUS status = ERROR_SUCCESS;
        DWORD dwCounterType = 0;
        HQUERY hQuery = NULL;
        HCOUNTER counter = NULL;
        PDH_FMT_COUNTERVALUE counterValue;

        //Get PDH query object
        status = PdhOpenQuery(NULL, 0, &hQuery);
        if ( status != ERROR_SUCCESS)
        {
            qDebug()<<__FUNCTION__<<" : PdhOpenQuery failed";
            return 0;
        }

        //Add Network  counter
        status = PdhAddCounter(hQuery, L"\\Network Interface(*)\\Bytes Sent/sec", 0, &counter);
        if (status != ERROR_SUCCESS )
        {
            qDebug()<<__FUNCTION__<<" : PdhAddCounter failed ";
            PdhCloseQuery(hQuery);
            return 0;
        }

        //Collect Data twice
        PdhCollectQueryData(hQuery);
        QThread::msleep(m_dataCollectionInterval);
        PdhCollectQueryData(hQuery);

        //Read Data
        PdhGetFormattedCounterValue(counter,PDH_FMT_DOUBLE,&dwCounterType, &counterValue);
        value = counterValue.doubleValue/1024.0f;

        PdhCloseQuery(hQuery);
    }

    return value;
}

/*
    返回需要异步监控的性能
*/
QSet<QWindowsPerformance::PerformanceType> QWindowsPerformance::monitoringPerformances()
{
    return m_monitoringPerformances;
}

/*
    添加需要异步监控的性能
*/
void QWindowsPerformance::addMonitoringPerformance(QWindowsPerformance::PerformanceType type)
{
    m_monitoringPerformances.insert(type);
}

/*
    清空移动监控的性能
*/
void QWindowsPerformance::clearMonitoringPerformance()
{
    m_monitoringPerformances.clear();
}

/*
    启动异步性能监控
*/
bool QWindowsPerformance::startMonitor()
{
    if(m_monitoringPerformances.size()<=0)
    {
        return false;
    }
    else
    {
        runFlag=true;
        start();
        return true;
    }
}

/*
    重启异步性能监控
*/
bool QWindowsPerformance::reStartMonitor()
{
    if(stopMonitor()){
        return startMonitor();
    }else{
        return false;
    }
}

/*
    暂停异步性能监控
*/
bool QWindowsPerformance::stopMonitor()
{
    runFlag = false;
    return wait(1500);
}

/*
    异步性能监控线程函数
*/
void QWindowsPerformance::run()
{
    QJsonObject dataObj;
    PDH_STATUS status = ERROR_SUCCESS;
    HQUERY hQuery = NULL;
    DWORD dwCounterType = 0;

    //Get PDH query object
    status = PdhOpenQuery(NULL, 0, &hQuery);
    if ( status != ERROR_SUCCESS)
    {
        QString errorMsg ="PdhOpenQuery failed";
        emit errorOccurred(errorMsg);
        qDebug()<<__FUNCTION__<<" : "<<errorMsg;
        return ;
    }

    //Add counters
    QMap<QWindowsPerformance::PerformanceType,HCOUNTER> counterMap;
    QVector<QWindowsPerformance::PerformanceType> othersVector;
    if(m_monitoringPerformances.find(QWindowsPerformance::CPUUsageRate)!=m_monitoringPerformances.end())
    {
        HCOUNTER counter = NULL;
        status = PdhAddCounter(hQuery, L"\\Processor(_Total)\\% Idle Time", 0, &counter);
        if ( status != ERROR_SUCCESS)
        {
            QString errorMsg ="PdhAddCounter failed CPUUsageRate";
            emit errorOccurred(errorMsg);
            qDebug()<<__FUNCTION__<<" : "<<errorMsg;
            PdhCloseQuery(hQuery);
            return ;
        }
        counterMap.insert(QWindowsPerformance::CPUUsageRate,counter);
    }
    if(m_monitoringPerformances.find(QWindowsPerformance::NetworkDownloadSpeed)!=m_monitoringPerformances.end())
    {
        HCOUNTER counter = NULL;
        status = PdhAddCounter(hQuery, L"\\Network Interface(*)\\Bytes Received/sec", 0, &counter);
        if ( status != ERROR_SUCCESS)
        {
            QString errorMsg ="PdhAddCounter failed NetworkDownloadSpeed";
            emit errorOccurred(errorMsg);
            qDebug()<<__FUNCTION__<<" : "<<errorMsg;
            PdhCloseQuery(hQuery);
            return ;
        }
        counterMap.insert(QWindowsPerformance::NetworkDownloadSpeed,counter);
    }
    if(m_monitoringPerformances.find(QWindowsPerformance::NetworkUploadSpeed)!=m_monitoringPerformances.end())
    {
        HCOUNTER counter = NULL;
        status = PdhAddCounter(hQuery, L"\\Network Interface(*)\\Bytes Sent/sec", 0, &counter);
        if ( status != ERROR_SUCCESS)
        {
            QString errorMsg ="PdhAddCounter failed NetworkUploadSpeed";
            emit errorOccurred(errorMsg);
            qDebug()<<__FUNCTION__<<" : "<<errorMsg;
            PdhCloseQuery(hQuery);
            return ;
        }
        counterMap.insert(QWindowsPerformance::NetworkUploadSpeed,counter);
    }
    if(m_monitoringPerformances.find(QWindowsPerformance::CPURunTime)!=m_monitoringPerformances.end())
    {
        othersVector.push_back(QWindowsPerformance::CPURunTime);
    }
    if(m_monitoringPerformances.find(QWindowsPerformance::MemoryUsageRate)!=m_monitoringPerformances.end())
    {
        othersVector.push_back(QWindowsPerformance::MemoryUsageRate);
    }
    if(m_monitoringPerformances.find(QWindowsPerformance::MemoryUsageAmount)!=m_monitoringPerformances.end())
    {
        othersVector.push_back(QWindowsPerformance::MemoryUsageAmount);
    }

    //Loop collect data
    while (runFlag)
    {
        PdhCollectQueryData(hQuery);
        QThread::msleep(m_dataCollectionInterval);
        PdhCollectQueryData(hQuery);

        //Get pdh data
        QMap<QWindowsPerformance::PerformanceType,HCOUNTER>::iterator it;
        for(it=counterMap.begin();it!=counterMap.end();it++)
        {
            if(it.key()==QWindowsPerformance::CPUUsageRate)
            {
                PDH_FMT_COUNTERVALUE value;
                PdhGetFormattedCounterValue(it.value(),PDH_FMT_DOUBLE,&dwCounterType, &value);
                dataObj["CPUUsageRate"] = 100-value.doubleValue;
            }
            else if(it.key()==QWindowsPerformance::NetworkDownloadSpeed)
            {
                PDH_FMT_COUNTERVALUE value;
                PdhGetFormattedCounterValue(it.value(),PDH_FMT_DOUBLE,&dwCounterType, &value);
                dataObj["NetworkDownloadSpeed"] = value.doubleValue/1024.0f;
            }
            else if(it.key()==QWindowsPerformance::NetworkUploadSpeed)
            {
                PDH_FMT_COUNTERVALUE value;
                PdhGetFormattedCounterValue(it.value(),PDH_FMT_DOUBLE,&dwCounterType, &value);
                dataObj["NetworkUploadSpeed"] = value.doubleValue/1024.0f;
            }
        }

        //Get Others data
        if(othersVector.contains(QWindowsPerformance::CPURunTime))
        {
            dataObj["CPURunTime"] = GetTickCount64()/1000.0f;
        }
        if(othersVector.contains(QWindowsPerformance::MemoryUsageRate))
        {
            MEMORYSTATUSEX memStatus;
            memStatus.dwLength = sizeof(memStatus);
            GlobalMemoryStatusEx(&memStatus);

            dataObj["MemoryUsageRate"] = (double)memStatus.dwMemoryLoad;
        }
        if(othersVector.contains(QWindowsPerformance::MemoryUsageAmount))
        {
            MEMORYSTATUSEX memStatus;
            memStatus.dwLength = sizeof(memStatus);
            GlobalMemoryStatusEx(&memStatus);

            dataObj["MemoryUsageAmount"] = (memStatus.ullTotalPhys - memStatus.ullAvailPhys)/1024.0f/1024.0f;
        }

        //Report data
        emit performanceReadReady(dataObj);
    }

    PdhCloseQuery(hQuery);
}
